Mineração de Dados 4

Os tópicos abordados serão:

Vamos instalar os pacotes necessários.

install.packages("ggplot2")   # pacote para análise gráfica
install.packages("gridExtra")   # pacote com função que permite múltiplos gráficos em uma mesma janela no ggplot2
install.packages("reshape2")   # pacote para transformação de dados
install.packages("ggcorrplot")   # pacote para visualizaçao de matrizes de correlações no ggplot2
install.packages("factoextra")  # pacote para visualização de resultados da análise de componentes principais

Vamos utilizar também o pacote stringr, instalado anteriormente.


Exemplo 5 - Qualidade de vinhos (2)

  • Voltaremos ao banco de dados sobre características de vinhos, que contém informações sobre variações de vinhos tintos e brancos do vinho português “Vinho Verde”.

  • Novamente, os dados podem ser obtidos em http://archive.ics.uci.edu/ml/datasets/Wine+Quality e já foram estudados por Cortez et al. (2009).

  • As variáveis são:

    • fixed acidity;
    • volatile acidity
    • citric acid;
    • residual sugar;
    • chlorides;
    • free sulfur dioxide;
    • total sulfur dioxide
    • density
    • pH;
    • sulphates;
    • alcohol;
    • quality (score between 0 and 10) (baseada em dados sensoriais).

Importando o banco de dados

Vamos importar o banco de dados, porém agora analisaremos os dados de vinho branco, em vez de vinho tinto.

Arquivo com extensão .csv separado por ponto-e-vírgula

Vamos importar a base de dados de vinho tinto.

white <- read.csv("http://im.ufrj.br/~joao/cienciadedados/winequality-white.csv",sep=";")
head(white)   # vislumbre dos dados
names(white)   # # nomes das colunas do objeto (variáveis)
##   fixed.acidity volatile.acidity citric.acid residual.sugar chlorides
## 1           7.0             0.27        0.36           20.7     0.045
## 2           6.3             0.30        0.34            1.6     0.049
## 3           8.1             0.28        0.40            6.9     0.050
## 4           7.2             0.23        0.32            8.5     0.058
## 5           7.2             0.23        0.32            8.5     0.058
## 6           8.1             0.28        0.40            6.9     0.050
##   free.sulfur.dioxide total.sulfur.dioxide density   pH sulphates alcohol
## 1                  45                  170  1.0010 3.00      0.45     8.8
## 2                  14                  132  0.9940 3.30      0.49     9.5
## 3                  30                   97  0.9951 3.26      0.44    10.1
## 4                  47                  186  0.9956 3.19      0.40     9.9
## 5                  47                  186  0.9956 3.19      0.40     9.9
## 6                  30                   97  0.9951 3.26      0.44    10.1
##   quality
## 1       6
## 2       6
## 3       6
## 4       6
## 5       6
## 6       6
##  [1] "fixed.acidity"        "volatile.acidity"     "citric.acid"         
##  [4] "residual.sugar"       "chlorides"            "free.sulfur.dioxide" 
##  [7] "total.sulfur.dioxide" "density"              "pH"                  
## [10] "sulphates"            "alcohol"              "quality"


Pacote ggplot2

  • O ggplot2 (Wickham 2016) é um pacote de visualização de dados para o R que tem ganhados muitos adeptos nos útimos anos por permitir a confecção de gráficos flexíveis e sofisticados.

  • É uma implementação da Grammar of Graphics (Wilkinson 2012): um esquema geral para visualização de dados que divide gráficos em componentes semânticos, como escalas e camadas.

  • Vamos prosseguir com uma análise exploratória dos dados utilizando o ggplot2.

Análise exploratória da qualidade do vinho (quality)

Primeiramente, vamos chamar o pacote ggplot2.

library("ggplot2")

A ideia do ggplot2 é que você construa gráficos por meio das mesmas componentes: um conjunto de dados, um sistema de coordenadas e geoms, que são a maneira como os dados serão representados, por exemplo, um histograma ou gráfico de dispersão.

Componentes estéticos (aesthetic) descrevem como as variáveis são mapeadas visualmente nos geoms; podem ser eixos, pontos, cores.

Inicialmente, vamos construir um histograma para as notas dos vinhos, variável que representa a qualidade (quality).

ggplot(white,aes(quality)) + geom_histogram(bins=7)

A função aes() pode ser chamada dentro da função geom_histograma() em vez de na função ggplot().

ggplot(white) + geom_histogram(aes(quality),bins=7)

Podemos modificas os eixos do histograma por meio das funções xlab() e ylab().

ggplot(white,aes(quality)) + geom_histogram(bins=7,col="white",fill="goldenrod") + xlab("Notas") + ylab("Frequência absoluta") + ggtitle("Histograma das notas dos vinhos")

Podemos alterar os nomes nos eixos e título conjuntamente por meio da função labs(), além de incluir legendas e subtítulo.

ggplot(white,aes(quality)) + 
  geom_histogram(bins=7,col=1,fill="turquoise") +
  labs(x="Notas",y="Frequência absoluta",title="Histograma das notas dos vinho",subtitle="(Qualidade)",caption="Figura: Histograma das notas dos vinhos dada por especialistas.")

A função theme() permite que mudemos a aparências de diversos elementos do gráfico.

Podemos ir acrescentando cada função (camada) ao objeto (gráfico) que queremos plotar e só depois plotá-lo.

histograma <- ggplot(white,aes(quality)) + 
  geom_histogram(bins=7,col=1,fill="firebrick") +
  labs(x="Notas",y="Frequência absoluta",title="Histograma das notas dos vinho",subtitle="(Qualidade)")

histograma <- histograma + theme(axis.title.x=element_text(color=2,size=20,face="italic"),
      axis.title.y=element_text(color=2,size=20,face="italic"),
      axis.text.x=element_text(size=17),
      axis.text.y=element_text(size=17))

histograma 

Vamos agora retirar a grade do histograma a alterar alguns parâmetros gráficos.

histograma <- ggplot(white,aes(quality)) + 
  geom_histogram(bins=7,col=1,fill="firebrick") +
  labs(x="Notas",y="Frequência absoluta",title="Histograma das notas dos vinho",subtitle="(Qualidade)")

histograma <- histograma + theme(axis.title.x=element_text(color=2,size=20,face="italic"),
      axis.title.y=element_text(color=2,size=20,face="italic"),
      axis.text.x=element_text(size=17),
      axis.text.y=element_text(size=17))

histograma

histograma <- histograma + theme(panel.grid.major=element_blank())

histograma

histograma <- histograma + theme(panel.grid.minor=element_blank())

histograma

histograma <- histograma + theme(axis.line=element_line(color=2,size=2))

histograma

Podemos escolher temas pré-definidos para os gráficos.

histograma <- ggplot(white,aes(quality)) + 
  geom_histogram(bins=7,col=1,fill="firebrick") +
  labs(x="Notas",y="Frequência absoluta",title="Histograma das notas dos vinho",subtitle="(Qualidade)")

histograma

histograma <- histograma + theme_bw()   # tema 1

histograma

histograma <- histograma + theme_gray()   # tema 2

histograma

histograma <- histograma + theme_dark()   # tema 3

histograma

Experimente theme_classic(), theme_linedraw(), theme_minimal() e theme_void().

Para fazer um histograma com a frequência relativa, podemos proceder como abaixo.

ggplot(white,aes(x=quality,y=..count../sum(..count..))) + geom_histogram(bins=7,col="white",fill="khaki") + labs(x="Notas",y="Frequência relativa") + theme_dark()

Vamos fazer também um polígono de frequências para as notas dos vinhos.

ggplot(white,aes(quality)) + geom_freqpoly(bins=7,lwd=1) +
  labs(x="Notas",y="Frequência absoluta") +
  theme(axis.title=element_text(size=16),axis.text=element_text(size=12))

Como a nota é uma variável discreta, pode ser útil, em vez de um histograma, fazer um gráfico de barras.

Vamos utilizar a função scale_*_discrete() mapeia valores discretos da variável em valores visuais.

ggplot(white,aes(quality)) + geom_bar(fill="mediumseagreen",col="mediumseagreen") +
  labs(x="Notas",y="Frequência absoluta") + scale_x_discrete(limits=3:9)
## Warning: Continuous limits supplied to discrete scale.
## Did you mean `limits = factor(...)` or `scale_*_continuous()`?

Análise exploratória das demais variáveis

Queremos construir histogramas em uma mesma janela. Para este fim, podemos utilizar a função grid.arrange() do pacote gridExtra (Auguie 2017).

Vamos chamá-lo.

library("gridExtra")

Se quisermos plotar os gráficos plotados anteriormente em uma mesma janela, podemos proceder como abaixo.

histograma <- ggplot(white,aes(quality)) + geom_histogram(bins=7,col="white",fill="khaki") +
  labs(x="Notas",y="Frequencia absoluta")

poligono <- ggplot(white,aes(quality)) + geom_freqpoly(bins=7,lwd=2) +
  labs(x="Notas",y="Frequencia absoluta")

barras <- ggplot(white,aes(quality)) + geom_bar(fill="mediumseagreen",col="mediumseagreen") +
  labs(x="Notas",y="Frequência absoluta") + scale_x_discrete(limits=3:9)
## Warning: Continuous limits supplied to discrete scale.
## Did you mean `limits = factor(...)` or `scale_*_continuous()`?
grid.arrange(histograma,poligono,nrow=1)

grid.arrange(histograma,poligono,ncol=1)

grid.arrange(histograma,poligono,barras,layout_matrix=
               matrix(c(1,1,
                        2,3),2,2,byrow=TRUE))

Vamos fazer histogramas para cada uma das variáveis em uma mesma janela.

n <- dim(white)[2]   # número de variáveis
graf <- list()
for(i in 1:n){
  graf[[i]] <- local({   # solução para o problema de ambiente: isola o bloco do for
    i <- i
    ggplot(white,aes(white[,i])) + geom_histogram(bins=7,col="black",fill="lightsteelblue1") +
    labs(x=names(white)[i],y="Frequência")
  })
}

grid.arrange(grobs=graf,nrow=3,ncol=4)   # grobs permite colocar a lista com todos os gráficos

Queremos agora calcular algumas medidas a respeito das variáveis do banco de dados, como média, mediana e desvio padrão.

Diferente do que foi feito anteriormente - em que utilizando o comando for para varrer os vetores e calcular as medidas - agora vamos utilizar a função apply().

A função apply() aplica uma função às linhas ou colunas de uma matriz ou data frame. Na maioria das situações, é mais eficiente que utilizar o comando for.

media <- apply(white,MARGIN=2,FUN="mean")   # aplica a função nas colunas
media
##        fixed.acidity     volatile.acidity          citric.acid 
##           6.85478767           0.27824112           0.33419151 
##       residual.sugar            chlorides  free.sulfur.dioxide 
##           6.39141486           0.04577236          35.30808493 
## total.sulfur.dioxide              density                   pH 
##         138.36065741           0.99402738           3.18826664 
##            sulphates              alcohol              quality 
##           0.48984688          10.51426705           5.87790935
dp <- apply(white,MARGIN=2,FUN="sd")
dp
##        fixed.acidity     volatile.acidity          citric.acid 
##          0.843868228          0.100794548          0.121019804 
##       residual.sugar            chlorides  free.sulfur.dioxide 
##          5.072057784          0.021847968         17.007137325 
## total.sulfur.dioxide              density                   pH 
##         42.498064554          0.002990907          0.151000600 
##            sulphates              alcohol              quality 
##          0.114125834          1.230620568          0.885638575
mediana <- apply(white,MARGIN=2,FUN="median")
mediana                 
##        fixed.acidity     volatile.acidity          citric.acid 
##              6.80000              0.26000              0.32000 
##       residual.sugar            chlorides  free.sulfur.dioxide 
##              5.20000              0.04300             34.00000 
## total.sulfur.dioxide              density                   pH 
##            134.00000              0.99374              3.18000 
##            sulphates              alcohol              quality 
##              0.47000             10.40000              6.00000
sumario <- data.frame("Média"=media,"Mediana"=mediana,"Desvio padrão"=dp)     
sumario
##                             Média   Mediana Desvio.padrão
## fixed.acidity          6.85478767   6.80000   0.843868228
## volatile.acidity       0.27824112   0.26000   0.100794548
## citric.acid            0.33419151   0.32000   0.121019804
## residual.sugar         6.39141486   5.20000   5.072057784
## chlorides              0.04577236   0.04300   0.021847968
## free.sulfur.dioxide   35.30808493  34.00000  17.007137325
## total.sulfur.dioxide 138.36065741 134.00000  42.498064554
## density                0.99402738   0.99374   0.002990907
## pH                     3.18826664   3.18000   0.151000600
## sulphates              0.48984688   0.47000   0.114125834
## alcohol               10.51426705  10.40000   1.230620568
## quality                5.87790935   6.00000   0.885638575

Análise bidimensional

Vamos agora fazer uma análise exploratória investigar se existe associação aparente entre as características do vinho branco e sua qualidade.

Como a variável quality (notas) é discreta, box-plots podem oferecer uma melhor visualização.

graf <- list()
for(i in 1:11){
  graf[[i]] <- local({
    i <- i
    ggplot(white,aes(x=as.factor(quality),y=white[,i])) +
      geom_boxplot(fill="khaki",outlier.size=1) +
      labs(x=names(white)[12],y=names(white)[i])
  })  
}

grid.arrange(grobs=graf,nrow=3,ncol=4)

Vamos calcular a correlação entre as notas e as demais variáveis.

cor(quality,white[,-12])
##      fixed.acidity volatile.acidity  citric.acid residual.sugar  chlorides
## [1,]    -0.1136628        -0.194723 -0.009209091    -0.09757683 -0.2099344
##      free.sulfur.dioxide total.sulfur.dioxide    density         pH  sulphates
## [1,]         0.008158067           -0.1747372 -0.3071233 0.09942725 0.05367788
##        alcohol
## [1,] 0.4355747

Podemos ver que a maior correlação é com a variável álcool (alcohol). Vamos investigar, em particular, tal relação por meio do box-plot com alguns elementos a mais.

ggplot(white,aes(x=as.factor(quality),y=alcohol)) + geom_boxplot(fill="goldenrod2",outlier.color="red") + labs(x="Notas",y="Álcool") +
  geom_jitter(position=position_jitter(0.2),col="red")

A segunda variável com maior correlação (em valor absoluto) com as notas é a variável a densidade(density).

Vamos fazer um gráfico que mostre a relação entre as três variáveis: quality, alcohol e density.

ggplot(white,aes(x=alcohol,y=density,col=as.factor(quality))) +
  geom_point(alpha=0.2,size=3) +
  labs(x="Álcool",y="Densidade")

A função scale_*_manual() mapeia manualmente valores da variável em valores visuais.

ggplot(white,aes(x=alcohol,y=density,col=as.factor(quality))) +
  geom_point(alpha=0.2,size=3) +
  labs(x="Álcool",y="Densidade") + scale_color_manual(values=heat.colors(7),name="Notas")

A função scale_*_gradientn() mapeia valores contínuos da variável em valores visuais por meio de uma palheta de cores.

ggplot(white,aes(x=alcohol,y=density,col=quality)) +
  geom_point(alpha=0.2,size=3) +
  labs(x="Álcool",y="Densidade") + scale_color_gradientn(colours=heat.colors(7),name="Notas")

Por fim, vamos exportar este último gráfico para um arquivo. Inicialmente, vamos gerar um arquivo PDF.

Exportado gráficos

disper <- ggplot(white,aes(x=alcohol,y=density,col=quality)) +
  geom_point(alpha=0.2,size=3) +
  labs(x="Álcool",y="Densidade") + scale_color_gradientn(colours=heat.colors(7),name="Notas")

ggsave("C:/Users/joaob/OneDrive/Desktop/Output/Dispersao.pdf",plot=disper,device="pdf",width=7,height=5)   # tamanho está em polegadas

Pode-se também exportar para arquivos com outras extensões. Para isto, basta escolher uma extensão diferente em device.


Redução de dimensão (análise de correlação)

  • Em geral, é muito comum encontrarmos em bancos de dados um número grande de variáveis.

  • É muito comum, neste contexto, que tais variáveis sejam correlacionadas; que forneçam, de certa forma, a mesma informação para um modelo preditivo ou de classificação, por exemplo.

  • Tais características dos dados podem levar a problemas como overfitting e problemas computacionais.

  • Para variáveis quantitativas, uma forma simples de verificar rendudâncias na informação é por meio de uma análise de correlação, como a feita anteriormente para os dados de vinho tinto.

Correlação para os dados de vinho branco

Primeiramente, vamos construir a matriz de correlação.

corrm <- cor(white)
corrm
##                      fixed.acidity volatile.acidity  citric.acid residual.sugar
## fixed.acidity           1.00000000      -0.02269729  0.289180698     0.08902070
## volatile.acidity       -0.02269729       1.00000000 -0.149471811     0.06428606
## citric.acid             0.28918070      -0.14947181  1.000000000     0.09421162
## residual.sugar          0.08902070       0.06428606  0.094211624     1.00000000
## chlorides               0.02308564       0.07051157  0.114364448     0.08868454
## free.sulfur.dioxide    -0.04939586      -0.09701194  0.094077221     0.29909835
## total.sulfur.dioxide    0.09106976       0.08926050  0.121130798     0.40143931
## density                 0.26533101       0.02711385  0.149502571     0.83896645
## pH                     -0.42585829      -0.03191537 -0.163748211    -0.19413345
## sulphates              -0.01714299      -0.03572815  0.062330940    -0.02666437
## alcohol                -0.12088112       0.06771794 -0.075728730    -0.45063122
## quality                -0.11366283      -0.19472297 -0.009209091    -0.09757683
##                        chlorides free.sulfur.dioxide total.sulfur.dioxide
## fixed.acidity         0.02308564       -0.0493958591          0.091069756
## volatile.acidity      0.07051157       -0.0970119393          0.089260504
## citric.acid           0.11436445        0.0940772210          0.121130798
## residual.sugar        0.08868454        0.2990983537          0.401439311
## chlorides             1.00000000        0.1013923521          0.198910300
## free.sulfur.dioxide   0.10139235        1.0000000000          0.615500965
## total.sulfur.dioxide  0.19891030        0.6155009650          1.000000000
## density               0.25721132        0.2942104109          0.529881324
## pH                   -0.09043946       -0.0006177961          0.002320972
## sulphates             0.01676288        0.0592172458          0.134562367
## alcohol              -0.36018871       -0.2501039415         -0.448892102
## quality              -0.20993441        0.0081580671         -0.174737218
##                          density            pH   sulphates     alcohol
## fixed.acidity         0.26533101 -0.4258582910 -0.01714299 -0.12088112
## volatile.acidity      0.02711385 -0.0319153683 -0.03572815  0.06771794
## citric.acid           0.14950257 -0.1637482114  0.06233094 -0.07572873
## residual.sugar        0.83896645 -0.1941334540 -0.02666437 -0.45063122
## chlorides             0.25721132 -0.0904394560  0.01676288 -0.36018871
## free.sulfur.dioxide   0.29421041 -0.0006177961  0.05921725 -0.25010394
## total.sulfur.dioxide  0.52988132  0.0023209718  0.13456237 -0.44889210
## density               1.00000000 -0.0935914935  0.07449315 -0.78013762
## pH                   -0.09359149  1.0000000000  0.15595150  0.12143210
## sulphates             0.07449315  0.1559514973  1.00000000 -0.01743277
## alcohol              -0.78013762  0.1214320987 -0.01743277  1.00000000
## quality              -0.30712331  0.0994272457  0.05367788  0.43557472
##                           quality
## fixed.acidity        -0.113662831
## volatile.acidity     -0.194722969
## citric.acid          -0.009209091
## residual.sugar       -0.097576829
## chlorides            -0.209934411
## free.sulfur.dioxide   0.008158067
## total.sulfur.dioxide -0.174737218
## density              -0.307123313
## pH                    0.099427246
## sulphates             0.053677877
## alcohol               0.435574715
## quality               1.000000000

Vamos criar um gráfico para a matriz de correlação utilizando o ggplot2 por meio da função geom_tile().

Como a entrada da função ggplot() precisamos de um data frame com três coluna correspondendo aos eixos x e y e às correlações.

Para este fim, utilizaremos a função melt() do pacote reshape2. Vamos chamá-lo.

library("reshape2")

Vamos agora transformar a matriz de correlaçao em um data frame.

corrm2 <- melt(corrm)
head(corrm2)
##                  Var1          Var2       value
## 1       fixed.acidity fixed.acidity  1.00000000
## 2    volatile.acidity fixed.acidity -0.02269729
## 3         citric.acid fixed.acidity  0.28918070
## 4      residual.sugar fixed.acidity  0.08902070
## 5           chlorides fixed.acidity  0.02308564
## 6 free.sulfur.dioxide fixed.acidity -0.04939586
ggplot(corrm2,aes(x=Var1,y=Var2,fill=value)) + geom_tile()

Vamos melhorar a visualização.

ggplot(corrm2,aes(x=Var1,y=Var2,fill=value)) + geom_tile() +
  labs(x="",y="") + theme(axis.text.x=element_text(angle=45,hjust=1,size=11),axis.text.y=element_text(size=11)) +
  scale_fill_gradientn(colours=heat.colors(20),name="Correlação")

Vamos tentar de outra forma utilizando a função scale_*_gradient2.

ggplot(corrm2,aes(x=Var1,y=Var2,fill=value)) + geom_tile() +
  labs(x="",y="") + theme(axis.text.x=element_text(angle=45,hjust=1,size=11),axis.text.y=element_text(size=11)) +
  scale_fill_gradient2(low="blue",high="red",mid="white",limit=c(-1,1))

Vamos fazer agora um gráfico mostrando somente a diagonal superior. O comando coorde_fixed deixa as escalas dos eixos x e y na escala original.

corrm[lower.tri(corrm)] <- NA   # NA na diagonal inferior
corrm2 <- melt(corrm,na.rm=TRUE)   # data frame sem os NA
ggplot(corrm2,aes(x=Var1,y=Var2,fill=value)) + geom_tile() +
  labs(x="",y="") + theme(axis.text.x=element_text(angle=45,hjust=1,size=9),axis.text.y=element_text(size=9),panel.background=element_blank()) +
  scale_fill_gradient2(low="blue",high="red",mid="white",limit=c(-1,1)) + coord_fixed()

Vamos fazer uma última versão com os valores incluídos por meio da função geom_text().

corrm[lower.tri(corrm)] <- NA   # NA na diagonal inferior
corrm2 <- melt(corrm,na.rm=TRUE)   # data frame sem os NA

ggplot(corrm2,aes(x=Var1,y=Var2,fill=value)) + geom_tile() +
  labs(x="",y="") + theme(axis.text.x=element_text(angle=45,hjust=1,size=9),axis.text.y=element_text(size=9),panel.background=element_blank()) +
  scale_fill_gradient2(low="blue",high="red",mid="white",limit=c(-1,1)) + coord_fixed() + geom_text(aes(x=Var1,y=Var2,label=round(value,2)),size=2.5)

O pacote ggcorrplot (Kassambara 2019) é útil por simplificar a confecção dos gráficos para as correlações utilizando o ggplot2.

Vamos chamá-lo.

library("ggcorrplot")

Vamos produzir alguns gráficos usando a matriz de correlação.

corrm <- cor(white)
ggcorrplot(corrm)

ggcorrplot(corrm,type="lower",method="circle")

ggcorrplot(corrm,type="upper",lab=TRUE,lab_size=2.5)


Redução de dimensão (análise de componentes principais)

  • A análise de componentes principais (ACP ou PCA, na sigla em inglês) é um método muito útil para redução de dimensão, principalmente quando o número de variáveis é muito alto.

  • O método é utilizado para variáveis quantitativas que são medidas na mesma escala.

  • Ele fornece variáveis que são combinações lineares de outras variáveis e que explicam a maior parte da variabilidade.

  • Em termos gerais, a PCA utiliza projeções para representar o conjunto de dados original, com muitas variáveis, em poucas variáveis.

  • Seja \(\Sigma\) uma matriz quadrada de dimensão \(n\times n\).

  • Um vetor \(\gamma\) de dimensão \(n\) não nulo é dito ser um autovetor de \(\Sigma\) se existe um escalar \(\lambda\) tal que \[\begin{align*} \Sigma\gamma &= \lambda\gamma\\ \Leftrightarrow(\Sigma - \lambda {\bf I})\gamma &= {\bf 0}\\ \Leftrightarrow |\Sigma - \lambda{\bf I}| &= 0. \end{align*}\]

  • O escalar \(\lambda\) é chamado autovalor e seu valor é encontrado a partir da equação \(|\Sigma - \lambda{\bf I}| = 0\), que é denominada equação característica.

  • O valor de \(\gamma\) associado a \(\lambda\) é encontrado então a partir da equação \((\Sigma - \lambda {\bf I})\gamma = {\bf 0}\).

  • Suponha que \(\Sigma\) seja uma matriz de covariância. Então, ela pode ser escrita como \[ \Sigma = \Gamma\Lambda\Gamma', \] em que \(\Gamma\) é uma matriz de dimensão \(n\times n\) cujas colunas são os autovetores da matriz \(\Sigma\) e \(\Lambda\) é uma matriz diagonal cujos elementos são os autovalores de \(\Sigma\) associados às colunas de \(\Gamma\).

  • O fato de \(\Sigma\) ser simétrica implica \(\Gamma'\Gamma={\bf I}\).

Autovalores e autovetores

Vamos considerar as duas variáveis no banco de dados de vinho branco com a maior correlação. Neste caso, density e residual.sugar.

cor(density,residual.sugar)
## [1] 0.8389665
ggplot(white,aes(density,residual.sugar)) + geom_point(col="aquamarine4")

Como as escalas são muito diferentes, vamos primeiramente padronizar as variáveis. Este passo não afeta a correlação, apenas como medimos a variabilidade.

den <- (density - mean(density))/sd(density)
res <- (residual.sugar - mean(residual.sugar))/sd(residual.sugar)
denres <- data.frame(den,res)
ggplot(denres,aes(den,res)) + geom_point(col="aquamarine4")

Vamos obter a matriz de covariância das duas variáveis, \(\Sigma\).

Sigma <- cov(denres)
Sigma
##           den       res
## den 1.0000000 0.8389665
## res 0.8389665 1.0000000

Vamos calcular os autovetores, \(\gamma_1\) e \(\gamma_2\), os autovalores, \(\lambda_1\) e \(\lambda_2\), da matriz de covariância por meio da função eigen().

e <- eigen(Sigma)
e
## eigen() decomposition
## $values
## [1] 1.8389665 0.1610335
## 
## $vectors
##           [,1]       [,2]
## [1,] 0.7071068 -0.7071068
## [2,] 0.7071068  0.7071068
Gamma <- e$vectors   # autovetores
Lambda <- e$values   # autovalores


  • Seja \({\bf x}\) a variável bivariada representando as variáveis density e residual.sugar padronizadas.

  • Se definirmos uma nova variável \[ {\bf y} = \Gamma'{\bf x}, \] temos que a matriz de covariância de \({\bf y}\) é \(\Lambda\), pois \[ Var({\bf y}) = \Gamma'\Sigma\Gamma = \Gamma'\Gamma\Lambda\Gamma'\Gamma=\Lambda. \]

Componentes principais

A matriz \(\Gamma'\) (matriz de rotação) projeta \(\bf x\) nas direções de maior variabilidade de forma que as componentes de \(\bf y\) sejam não correlacionadas.

Tais direções são dadas pelos autovetores \(\gamma_1\) e \(\gamma_2\), que são ortogonais e denominadas componentes principais.

A primeira componente principal é o autovetor associado ao maior autovalor e a segunda componente principal é o autovetor associado ao segundo maior autovalor e assim por diante, caso houvesse mais de duas componentes principais.

ggplot(denres,aes(den,res)) + geom_point(col="aquamarine4") +
  geom_segment(x=0,xend=0.7071,y=0,yend=0.7071,size=1.5) +
  geom_segment(x=0,xend=-0.7071,y=0,yend=0.7071,size=1.5) +
  coord_fixed()

Podemos então projetar cada par de valores das variáveis density e residual.sugar

denres2 <- denres   # declarando o novo data frame
for(i in 1:length(density)){
  denres2[i,] <- t(Gamma)%*%as.numeric(denres[i,])
}

ggplot(denres2,aes(den,res)) + geom_point(col="cornflowerblue") +
  coord_fixed()   # escala original

ggplot(denres2,aes(den,res)) + geom_point(col="cornflowerblue")   # escala de melhor visualização

A primeira componente explica a maior parte da variabilidade. Nesta caso, parece razoável considerar somente a primeira variável em termos das componentes principais e assim, reduzirmos a dimensão do banco de dados.

Lambda[1]/sum(Lambda)
## [1] 0.9194832

O conjunto de dados representado por \(\bf y\) contém a mesma informação que o conjunto de dados representado por \(\bf x\), pois a tranformação é bijetiva.

Podemos obter \(\bf x\) de volta ao fazermos \[ {\bf z} = \Gamma {\bf y} = \Gamma \Gamma' {\bf x} = {\bf x.} \]

Análise de componentes principais

Podemos fazer uma ACP no R de maneira simples utilizando a função prcomp().

Para facilitar a visualização e análise dos resultados, vamos utilizar o pacote factoextra (Kassambara e Mundt 2020), que possui alguns gráficos úteis para a ACP.

Vamos chamá-lo.

library("factoextra")
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa

Vamos utilizar a função prcomp() para fazermos a análise.

acp <- prcomp(denres)   # ACP
acp
## Standard deviations (1, .., p=2):
## [1] 1.3560850 0.4012899
## 
## Rotation (n x k) = (2 x 2):
##            PC1        PC2
## den -0.7071068 -0.7071068
## res -0.7071068  0.7071068
names(acp)   
## [1] "sdev"     "rotation" "center"   "scale"    "x"
acp$rotation   # matriz de rotação (matriz de autovetores)
##            PC1        PC2
## den -0.7071068 -0.7071068
## res -0.7071068  0.7071068
head(acp$x)   # valores em termos das componentes principais
##             PC1         PC2
## [1,] -3.6432511  0.34633181
## [2,]  0.6744540 -0.66150942
## [3,] -0.3244914 -0.18268544
## [4,] -0.6657604 -0.07783534
## [5,] -0.6657604 -0.07783534
## [6,] -0.3244914 -0.18268544

Vamos investigar a porcentagem da variabilidade explicada por cada componente.

fviz_eig(acp)

Vamos investigar os elementos do banco de dados em termos das componentes principais.

fviz_pca_ind(acp)  

No gráfico a seguir podemos ver a relação entre as componentes principais e as variáveis originais.

Variáveis positivamente correlacionadas apontam para o mesmo lado no gráfico.

Varáveis negativamente correlacionadas apontam para lados opostos.

As variáveis que mais contribuem para a componente principal apontam para o “lado” da componente (sentido positivo ou negativo).

fviz_pca_var(acp)

O gráfico a seguir se chama biplot e combina as informações dos dois gráficos anteriores.

fviz_pca_biplot(acp)

Análise de componentes principais (banco de dados completos)

Vamos agora fazer uma ACP para todo o banco de dados de vinho branco, com exceção da variável quality, que representa a nota dada ao vinho.

Primeiramente, como os valores das variáveis estão em escalas muito diferentes, padronizaremos todas.

white2 <- white[,-12]
names(white2)
##  [1] "fixed.acidity"        "volatile.acidity"     "citric.acid"         
##  [4] "residual.sugar"       "chlorides"            "free.sulfur.dioxide" 
##  [7] "total.sulfur.dioxide" "density"              "pH"                  
## [10] "sulphates"            "alcohol"
white3 <- white2

for(i in 1:11){
  med <- mean(white2[,i])
  dp <- sd(white2[,i])
  white3[,i] <- (white2[,i] - med)/dp   # padronizando as variáveis
}                

Vamos prosseguir com a ACP.

acp <- prcomp(white3)
acp
## Standard deviations (1, .., p=11):
##  [1] 1.7950638 1.2550856 1.1052924 1.0092187 0.9865772 0.9688867 0.8524072
##  [8] 0.7741825 0.6435399 0.5380401 0.1436979
## 
## Rotation (n x k) = (11 x 11):
##                               PC1          PC2        PC3         PC4
## fixed.acidity         0.157218451 -0.587558208 -0.1213683 -0.01858383
## volatile.acidity      0.005089494  0.051728054  0.5909715 -0.27411517
## citric.acid           0.144049843 -0.345294562 -0.5043969 -0.14851432
## residual.sugar        0.427408368  0.008749392  0.2143199  0.27376531
## chlorides             0.212011065 -0.008800308  0.1023674 -0.71071228
## free.sulfur.dioxide   0.300334387  0.290355136 -0.2794101  0.30558549
## total.sulfur.dioxide  0.406652203  0.244032391 -0.1243753  0.06045562
## density               0.511523597  0.006296796  0.1292029  0.02206110
## pH                   -0.128831885  0.581344397 -0.1266715 -0.09775335
## sulphates             0.043379327  0.222695370 -0.4332440 -0.44205953
## alcohol              -0.437237835 -0.035568666 -0.1059032  0.14107870
##                              PC5        PC6         PC7         PC8         PC9
## fixed.acidity        -0.25104839 -0.1035307  0.19784897  0.58835527 -0.33052283
## volatile.acidity     -0.64261658  0.1223385 -0.26935495  0.02837266  0.14590968
## citric.acid          -0.05390510  0.1320967 -0.70548123 -0.15228698  0.20201133
## residual.sugar       -0.01139144 -0.2894469 -0.21275955 -0.38818585 -0.40896853
## chlorides             0.32862831  0.3958211  0.07948377 -0.10015094 -0.39353539
## free.sulfur.dioxide  -0.17691226  0.4944936  0.16677879 -0.08179901 -0.14407339
## total.sulfur.dioxide -0.29300991  0.2763199  0.06772962  0.24731437  0.15454024
## density               0.08458824 -0.3276509 -0.11038544  0.06902650 -0.08788799
## pH                    0.11982553 -0.1933412 -0.42731310  0.53388135 -0.26129767
## sulphates            -0.40058526 -0.4810392  0.30856238 -0.27039413  0.01169757
## alcohol              -0.33741948  0.1392842 -0.12892247 -0.19585929 -0.62109070
##                             PC10         PC11
## fixed.acidity        -0.13170530 -0.171290475
## volatile.acidity     -0.22372176 -0.017056659
## citric.acid          -0.03735137 -0.009721121
## residual.sugar        0.09446795 -0.490225929
## chlorides             0.05337405 -0.025399445
## free.sulfur.dioxide  -0.56745057  0.030908440
## total.sulfur.dioxide  0.70912033 -0.035560953
## density              -0.06837403  0.759779368
## pH                   -0.11073292 -0.141197197
## sulphates            -0.05770758 -0.041832843
## alcohol               0.27260860  0.357961330

Vamos investigar a porcentagem da variabilidade explicada por cada componente principal.

fviz_eig(acp)

Vamos investigar porcentagem de variação acumulada.

dp <- acp$sdev
dpac <- cumsum(acp$sdev)/sum(acp$sdev)   # cumsum retorna a soma acumulada
data.frame("dp"=dp,"porce"=paste(round(dpac*100,2),"%"))
##           dp   porce
## 1  1.7950638 17.82 %
## 2  1.2550856 30.28 %
## 3  1.1052924 41.26 %
## 4  1.0092187 51.28 %
## 5  0.9865772 61.07 %
## 6  0.9688867 70.69 %
## 7  0.8524072 79.16 %
## 8  0.7741825 86.84 %
## 9  0.6435399 93.23 %
## 10 0.5380401 98.57 %
## 11 0.1436979   100 %

Vamos ver agora como as variaveis originais se relacionam com as duas componentes princiais.

fviz_pca_var(acp,col.var="contrib",gradient.cols=heat.colors(3))

Vamos prosseguir agora com o biplot. No gráfico, valores próximos são similares.

fviz_pca_biplot(acp)

Podemos investigar agora se existe alguma relação aparente entre as componentes principais e as notas dos vinhos.

fviz_pca_biplot(acp,col.ind=as.factor(quality),geom="point")

Com muitas notas possíveis, pode ser difícil verificar se há algum padrão. Vamos criar uma nova variável em que categorizamos os vinhos como “notas baixas” e “notas altas”.

notacat <- quality
notacat[quality<6] <- "baixo"
notacat[quality>=6] <- "alto"
fviz_pca_biplot(acp,col.ind=notacat,geom="point")


Exemplo 6 - Serviços de utilidade pública

  • O banco de dados corresponde a variáveis associadas a 22 empresas de utilidade pública dos Estados Unidos.

  • Os dados estão disponíveis em Shmueli et al. (2017).

  • As variáveis são:

    • Fixed - fixed-charge covering ratio (income/debt);
    • RoR - rate of return on capital;
    • Cost - cost per kilowatt capacity in place; Load = annual load factor;
    • Demand - peak kilowatthour demand growth from 1974 to 1975;
    • Sales - sales (kilowatthour use per year);
    • Nuclear - percent nuclear;
    • Fuel Cost - total fuel costs (cents per kilowatthour);

Importando o banco de dados

Arquivo com extensão .txt separado por tabulação

Vamos importar a base de dados.

uti <- read.csv("http://im.ufrj.br/~joao/cienciadedados/utilities.txt",sep="\t")
uti   # vislumbre dos dados
names(uti)   # # nomes das colunas do objeto (variáveis)
##                          Company Fixed  RoR Cost Load Demand Sales Nuclear
## 1         Arizona Public Service  1.06  9.2  151 54.4    1.6  9077     0.0
## 2              Boston Edison Co.  0.89 10.3  202 57.9    2.2  5088    25.3
## 3          Central Louisiana Co.  1.43 15.4  113 53.0    3.4  9212     0.0
## 4        Commonwealth Edison Co.  1.02 11.2  168 56.0    0.3  6423    34.3
## 5   Consolidated Edison Co. (NY)  1.49  8.8  192 51.2    1.0  3300    15.6
## 6      Florida Power & Light Co.  1.32 13.5  111 60.0   -2.2 11127    22.5
## 7          Hawaiian Electric Co.  1.22 12.2  175 67.6    2.2  7642     0.0
## 8                Idaho Power Co.  1.10  9.2  245 57.0    3.3 13082     0.0
## 9         Kentucky Utilities Co.  1.34 13.0  168 60.4    7.2  8406     0.0
## 10    Madison Gas & Electric Co.  1.12 12.4  197 53.0    2.7  6455    39.2
## 11              Nevada Power Co.  0.75  7.5  173 51.5    6.5 17441     0.0
## 12      New England Electric Co.  1.13 10.9  178 62.0    3.7  6154     0.0
## 13     Northern States Power Co.  1.15 12.7  199 53.7    6.4  7179    50.2
## 14   Oklahoma Gas & Electric Co.  1.09 12.0   96 49.8    1.4  9673     0.0
## 15    Pacific Gas & Electric Co.  0.96  7.6  164 62.2   -0.1  6468     0.9
## 16 Puget Sound Power & Light Co.  1.16  9.9  252 56.0    9.2 15991     0.0
## 17  San Diego Gas & Electric Co.  0.76  6.4  136 61.9    9.0  5714     8.3
## 18              The Southern Co.  1.05 12.6  150 56.7    2.7 10140     0.0
## 19           Texas Utilities Co.  1.16 11.7  104 54.0   -2.1 13507     0.0
## 20  Wisconsin Electric Power Co.  1.20 11.8  148 59.9    3.5  7287    41.1
## 21       United Illuminating Co.  1.04  8.6  204 61.0    3.5  6650     0.0
## 22 Virginia Electric & Power Co.  1.07  9.3  174 54.3    5.9 10093    26.6
##    Fuel.cost
## 1      0.628
## 2      1.555
## 3      1.058
## 4      0.700
## 5      2.044
## 6      1.241
## 7      1.652
## 8      0.309
## 9      0.862
## 10     0.623
## 11     0.768
## 12     1.897
## 13     0.527
## 14     0.588
## 15     1.400
## 16     0.620
## 17     1.920
## 18     1.108
## 19     0.636
## 20     0.702
## 21     2.116
## 22     1.306
## [1] "Company"   "Fixed"     "RoR"       "Cost"      "Load"      "Demand"   
## [7] "Sales"     "Nuclear"   "Fuel.cost"


Análise exploratória

Box-plots das variáveis por empresa

Vamos ver o comportamento de cada variável por empresa.

a <- ggplot(uti,aes(Company,weight=Fixed)) + geom_bar(fill="khaki",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))

b <- ggplot(uti,aes(Company,weight=RoR)) + geom_bar(fill="coral",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))

c <- ggplot(uti,aes(Company,weight=Cost)) + geom_bar(fill="grey70",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))

d <- ggplot(uti,aes(Company,weight=Load)) + geom_bar(fill="grey40",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))

e <- ggplot(uti,aes(Company,weight=Demand)) + geom_bar(fill="orange",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))

f <- ggplot(uti,aes(Company,weight=Sales)) + geom_bar(fill="blue",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))

g <- ggplot(uti,aes(Company,weight=Nuclear)) + geom_bar(fill="yellow",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))

h <- ggplot(uti,aes(Company,weight=Fuel.cost)) + geom_bar(fill="grey70",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))
a

b

c

d

e

f

g

h


Análise de componentes principais para identificação de agrupamentos

  • A ACP, além do seu papel de redução de dimensão, é útil para visualização de dados em alta dimensão por meio da representação destes em dimensões menores.

  • Assim, é possível utilizar a ACP para visualizar possíveis agrupamentos ou clusters.

Identificando agrupamentos visualmente

Vamos tentar identificar as empresas de serviço público que são semelhantes.

Em um primeiro passo, para facilitar a visualização, vamos nomear as linhas do data frame e encurtar o nome por meio da função word() do pacote stringr (Wickham 2019).

library("stringr")
uti2 <- uti[,-1]    # retirando a coluna de nomes
nomes <- word(uti[,1])   # pegando a primeira palavra
nomes[c(12,17,18)] <- paste(nomes[c(12,17,18)],word(uti[c(12,17,18),1],2))   # acrescentando a segunda palavra em alguns nomes
nomes
##  [1] "Arizona"      "Boston"       "Central"      "Commonwealth" "Consolidated"
##  [6] "Florida"      "Hawaiian"     "Idaho"        "Kentucky"     "Madison"     
## [11] "Nevada"       "New England"  "Northern"     "Oklahoma"     "Pacific"     
## [16] "Puget"        "San Diego"    "The Southern" "Texas"        "Wisconsin"   
## [21] "United"       "Virginia"
row.names(uti2) <- nomes   # nomeando as linhas do data frame

Vamos prosseguir com a ACP e investigar os resultados.

acp <- prcomp(uti2,scale=TRUE)   # scale padroniza as variáveis  
acp
## Standard deviations (1, .., p=8):
## [1] 1.4740918 1.3785018 1.1504236 0.9983701 0.8056180 0.7560814 0.4652989
## [8] 0.4115657
## 
## Rotation (n x k) = (8 x 8):
##                   PC1         PC2         PC3         PC4        PC5
## Fixed      0.44554526 -0.23217669  0.06712849 -0.55549758  0.4008403
## RoR        0.57119021 -0.10053490  0.07123367 -0.33209594 -0.3359424
## Cost      -0.34869054  0.16130192  0.46733094 -0.40908380  0.2685680
## Load      -0.28890116 -0.40918419 -0.14259793 -0.33373941 -0.6800711
## Demand    -0.35536100  0.28293270  0.28146360 -0.39139699 -0.1626375
## Sales      0.05383343  0.60309487 -0.33199086 -0.19086550 -0.1319721
## Nuclear    0.16797023 -0.08536118  0.73768406  0.33348714 -0.2496462
## Fuel.cost -0.33584032 -0.53988503 -0.13442354 -0.03960132  0.2926660
##                   PC6         PC7         PC8
## Fixed     -0.00654016  0.20578234 -0.48107955
## RoR       -0.13326000 -0.15026737  0.62855128
## Cost       0.53750238 -0.11762875  0.30294347
## Load       0.29890373  0.06429342 -0.24781930
## Demand    -0.71916993 -0.05155339 -0.12223012
## Sales      0.14953365  0.66050223  0.10339649
## Nuclear    0.02644086  0.48879175 -0.08466572
## Fuel.cost -0.25235278  0.48914707  0.43300956
fviz_eig(acp)

fviz_pca_var(acp,col.var="contrib",gradient.cols=heat.colors(5))

fviz_pca_ind(acp,repel=TRUE,col.ind="contrib",gradient.cols=heat.colors(5))

fviz_pca_biplot(acp,repel=TRUE,col.ind="cos2",gradient.cols=heat.colors(5))

Vamos investigar se existe alguma relação entre os grupos e sua região.

reg <- read.table("http://im.ufrj.br/~joao/cienciadedados/regioes.txt")   # regiões de cada em empresa nos EUA
reg
##              V1
## 1         Oeste
## 2      Nordeste
## 3           Sul
## 4  Centro-Oeste
## 5      Nordeste
## 6           Sul
## 7         Oeste
## 8         Oeste
## 9           Sul
## 10 Centro-Oeste
## 11        Oeste
## 12     Nordeste
## 13 Centro-Oeste
## 14          Sul
## 15        Oeste
## 16        Oeste
## 17        Oeste
## 18          Sul
## 19          Sul
## 20 Centro-Oeste
## 21        Oeste
## 22          Sul
fviz_pca_ind(acp,repel=TRUE,col.ind=reg[,1])

fviz_pca_ind(acp,repel=TRUE,col.ind=reg[,1],addEllipses=TRUE)
## Too few points to calculate an ellipse


Análise de componentes principais para previsão

Prevendo coordenadas

Vamos inicialmente considerar o conjunto de dados sem duas empresas: Puget Sound Power & Light Co. e Wisconsin Electric Power Co..

uti3 <- uti2[-c(16,20),]
head(uti3)
##              Fixed  RoR Cost Load Demand Sales Nuclear Fuel.cost
## Arizona       1.06  9.2  151 54.4    1.6  9077     0.0     0.628
## Boston        0.89 10.3  202 57.9    2.2  5088    25.3     1.555
## Central       1.43 15.4  113 53.0    3.4  9212     0.0     1.058
## Commonwealth  1.02 11.2  168 56.0    0.3  6423    34.3     0.700
## Consolidated  1.49  8.8  192 51.2    1.0  3300    15.6     2.044
## Florida       1.32 13.5  111 60.0   -2.2 11127    22.5     1.241

Vamos fazer a ACP sem essas duas empresas e investigar os resultados.

acp <- prcomp(uti3,scale=TRUE)
acp
## Standard deviations (1, .., p=8):
## [1] 1.5183992 1.3274199 1.2201174 0.8931163 0.8217833 0.7689916 0.4917071
## [8] 0.3709790
## 
## Rotation (n x k) = (8 x 8):
##                   PC1         PC2         PC3        PC4         PC5
## Fixed      0.32807762 -0.52457384  0.02740780 -0.3118825  0.10780600
## RoR        0.47988924 -0.34528770  0.08228092 -0.4079591 -0.03823866
## Cost      -0.35311053  0.05387607  0.44875193 -0.2236685  0.67997558
## Load      -0.37612743 -0.28612991 -0.32115981 -0.2723371  0.33497630
## Demand    -0.30728174  0.27427882  0.20849305 -0.7082643 -0.51891188
## Sales      0.30328128  0.53393373 -0.26183688 -0.2041573  0.24423665
## Nuclear    0.03973451 -0.10849429  0.72388842  0.2396766 -0.11784750
## Fuel.cost -0.45599570 -0.38566906 -0.22784731  0.1064908 -0.26368662
##                   PC6          PC7         PC8
## Fixed     -0.48725984  0.165081964  0.49281754
## RoR        0.33055559 -0.029403836 -0.60472158
## Cost      -0.27228043 -0.004129898 -0.29066123
## Load       0.61919899  0.028182327  0.32083635
## Demand    -0.04196668 -0.024029612  0.11676160
## Sales      0.03735313  0.671971333  0.01020928
## Nuclear    0.38193238  0.441341949  0.22505056
## Fuel.cost -0.21618981  0.569356172 -0.37368103
fviz_eig(acp)

fviz_pca_biplot(acp,repel=TRUE,col.ind="cos2",gradient.cols=heat.colors(5))

Queremos agora prever as coordenadas no gráfico das empresas que foram retiradas dos banco de dados utilizando apenas dados das empresas as quais consideramos anteriormente.

utinew <- uti2[c(16,20),]
utinew
##           Fixed  RoR Cost Load Demand Sales Nuclear Fuel.cost
## Puget      1.16  9.9  252 56.0    9.2 15991     0.0     0.620
## Wisconsin  1.20 11.8  148 59.9    3.5  7287    41.1     0.702

Vamos projetar os valores das variáveis nas novas coordenadas.

prev <- predict(acp,newdata=utinew)
prev
##                  PC1        PC2       PC3        PC4        PC5       PC6
## Puget     -0.3916282  2.3499131 0.6306031 -2.6119347  1.2889429 -1.053420
## Wisconsin  0.5401103 -0.6837701 1.3172558 -0.1064522 -0.2597302  1.300161
##                 PC7        PC8
## Puget     0.6368441 0.09037778
## Wisconsin 0.1812736 1.02826881

Agora vamos plotar os pontos previstos no biplot.

graf <- fviz_pca_biplot(acp,repel=TRUE,col.ind="cos2",gradient.cols=heat.colors(5))
fviz_add(graf,prev,repel=TRUE)   # adicionado os novos pontos


Referências

Auguie, B. 2017. gridExtra: Miscellaneous Functions for "Grid" Graphics. https://CRAN.R-project.org/package=gridExtra.

Cortez, P., A. Cerdeira, F. Almeida, T. Matos, e J. Reis. 2009. “Modeling wine preferences by data mining from physicochemical properties”. Decision Support Systems 47: 547–53.

Kassambara, A. 2019. ggcorrplot: Visualization of a Correlation Matrix using ’ggplot2’. https://CRAN.R-project.org/package=ggcorrplot.

Kassambara, A., e F. Mundt. 2020. factoextra: Extract and Visualize the Results of Multivariate Data Analyses. https://CRAN.R-project.org/package=factoextra.

Shmueli, G., P. C. Bruce, I. Yahav, N. R. Patel, e K. C. Lichtendahl Jr. 2017. Data mining for business analytics: concepts, techniques, and applications in R. John Wiley & Sons.

Wickham, H. 2016. ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. https://ggplot2.tidyverse.org.

———. 2019. stringr: Simple, Consistent Wrappers for Common String Operations. https://CRAN.R-project.org/package=stringr.

Wilkinson, L. 2012. “The grammar of graphics”. In Handbook of Computational Statistics, 375–414. Springer.